package com.koron.css2.newProjectCenter.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.koron.css2.ImportExcelInterface;
import com.koron.css2.baseConfig.impl.GenerateNumber;
import com.koron.css2.baseConfig.impl.GenerateNumberImpl;
import com.koron.css2.baseConfig.mapper.ConfigMapper;
import com.koron.css2.baseConfig.mapper.WaterTypeMapper;
import com.koron.css2.baseConfig.queryBean.WaterTypeQueryBean;
import com.koron.css2.baseConfig.vo.WaterTypeVO;
import com.koron.css2.clientCenter.bean.UserBean;
import com.koron.css2.clientCenter.mapper.UserInfoMapper;
import com.koron.css2.clientCenter.queryBean.UserInfoQueryBean;
import com.koron.css2.common.dto.HeaderInfoDto;
import com.koron.css2.meterService.bean.query.MsInfoQueryBean;
import com.koron.css2.meterService.dto.MsInfoDto;
import com.koron.css2.meterService.mapper.MsInfoMapper;
import com.koron.css2.newProjectCenter.bean.PjMeter;
import com.koron.css2.newProjectCenter.bean.query.PjMeterQuery;
import com.koron.css2.newProjectCenter.exception.UserNoException;
import com.koron.css2.newProjectCenter.mapper.PjMeterMapper;
import com.koron.css2.serviceManage.bean.CodeRuleBean;
import com.koron.css2.serviceManage.bean.RequestBean;
import com.koron.css2.serviceManage.bean.TWaterCompanyBean;
import com.koron.css2.serviceManage.bean.UserInfoBean;
import com.koron.css2.serviceManage.mapper.CodeRuleMapper;
import com.koron.css2.serviceManage.mapper.TWaterCompanyMapper;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.css2.serviceManage.vo.DictionaryVO;
import com.koron.css2.systemManage.bean.OrgUserBean;
import com.koron.css2.systemManage.bean.OrgUserQueryBean;
import com.koron.css2.systemManage.mapper.OrgUserMapper;
import com.koron.util.Constant;
import com.koron.util.DBSourceUtils;
import com.koron.util.Tools;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.springframework.web.multipart.MultipartFile;
import org.swan.bean.MessageBean;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class PjMeterInstallBuildImport implements ImportExcelInterface {
    //用户编号的编码规则
    public static final String USER_NO_RULE_CODE = "USER_INFO";
    //判断参数【是否允许水表出库环节编辑用户编号  0是 1否】
    private static final String PJ_METER_INSTALL = "PJ_METER_INSTALL";
    //允许水表出库环节编辑用户编号
    private static final String CONFIG_OPEN = "0";

    @Override
    public MessageBean<?> importExel(SessionFactory factory, UserInfoBean userInfo, RequestBean req, List<Map<String, String>> data, MultipartFile file) {
        try {
            //导入接口入参接收
            PjMeterQuery pjMeterQuery = JsonUtils.objectToPojo(req.getData(), PjMeterQuery.class);
            MsInfoMapper msInfoMapper = factory.getMapper(MsInfoMapper.class);
            WaterTypeMapper waterTypeMapper = factory.getMapper(WaterTypeMapper.class);
            List<PjMeter> pjMeterList = new ArrayList<>();
            OrgUserMapper orgUserMapper = factory.getMapper(OrgUserMapper.class);
            ConfigMapper configMapper = factory.getMapper(ConfigMapper.class);
            //获取参数【是否允许水表出库环节编辑用户编号  0是 1否】配置
            String config = configMapper.getConfigValueByName(PJ_METER_INSTALL);
            if (data.size() >= 2) {
                for (int i = 0; i < data.size() - 1; i++) {
                    // 水表表身码
                    String factoryNo1 = data.get(i).get("factoryNo");
                    if (StringUtils.isEmpty(factoryNo1)){
                        return MessageBean.create(Constant.MESSAGE_INT_FAIL, "第" + (i + 1) + "行：表身码不能为空", null);
                    }
                    for (int j = i + 1; j < data.size(); j++) {
                        String factoryNo2 = data.get(j).get("factoryNo");
                        if (Objects.equals(factoryNo1, factoryNo2)) {
                            return MessageBean.create(Constant.MESSAGE_INT_FAIL, "第" + (i + 1) + "行与" + (j + 1) + "行表身码相同", null);
                        }
                    }
                }
            }

            //如果配置开启，需要校验用户编号是否符合规则
            if (CONFIG_OPEN.equals(config)) {
                checkImportUserNo(factory, data, pjMeterQuery, userInfo, false);
            }

            //表井模式数据字典
            Map<String, String> BJMSMap = Tools.listDicByCode(factory, "BJMS").stream().collect(Collectors.toMap(DictionaryVO::getName,DictionaryVO::getValue));

            //表井形式数据字典
            Map<String, String> BJXSMap = Tools.listDicByCode(factory, "BJXS").stream().collect(Collectors.toMap(DictionaryVO::getName,DictionaryVO::getValue));

            // 查询出用水类型信息
            List<WaterTypeVO> waterTypeList = waterTypeMapper.findAllWaterType(new WaterTypeQueryBean());

            // 将水类型信息集合转成Map
            Map<String, String> waterTypeMap = waterTypeList.stream().collect(Collectors.toMap(WaterTypeVO::getWaterTypeName, WaterTypeVO::getId));

            // 查询水表信息
            List<String> factoryNoList = data.stream().map(t -> t.get("factoryNo")).collect(Collectors.toList());
            MsInfoQueryBean msInfoQuery = new MsInfoQueryBean();
            msInfoQuery.setFactoryNoList(factoryNoList);
            List<MsInfoDto> msInfoList = msInfoMapper.selectMsInfoListByFuzzy(msInfoQuery);
            Map<String, MsInfoDto> msInfoMap = msInfoList.stream().collect(Collectors.toMap(MsInfoDto::getFactoryNo, Function.identity()));

            // 查询出导入的文件中施工人员信息
            Map<String, String> orgUserMap = null;
            List<String> meterBuilderList = data.stream().map(t -> t.get("meterBuilder")).collect(Collectors.toList());
            if (meterBuilderList.size() > 0){
                OrgUserQueryBean orgUserQuery = new OrgUserQueryBean();
                orgUserQuery.setUserNames(meterBuilderList);
                List<OrgUserBean> orgUserList = orgUserMapper.selectList(orgUserQuery);
                orgUserMap = orgUserList.stream().collect(Collectors.toMap(OrgUserBean::getUserName, OrgUserBean::getAccount));
            }

            //创建一个计数器用于记录行数，准确提示导入数据错误行数
            int row = 1;
            // 1. 循环获取数据
            //捕获异常对导入数据进行准确提示
            try {
                for (Map<String, String> map : data) {
                    UserBean userBean = new UserBean();
                    PjMeter pjMeter = new PjMeter();
                    MsInfoDto msInfoDto = new MsInfoDto();

                    // 表井模式
                    String meterBjmsName = map.get("meterBjmsName");
                    if (StringUtils.isNotBlank(meterBjmsName)) {
                       //判断表井模式是否存在
                        if (!BJMSMap.containsKey(meterBjmsName)) {
                            throw new RuntimeException("请输入正确的表井模式");
                        }
                        userBean.setMeterBjms(BJMSMap.get(meterBjmsName));
                    }

                    // 用水类型
                    String userWaterTypeName = map.get("userWaterTypeName");
                    if (StringUtils.isNotEmpty(userWaterTypeName)){
                        if (StringUtils.isEmpty(waterTypeMap.get(userWaterTypeName))){
                            throw new RuntimeException("系统中不存在该用水类型");
                        }
                        userBean.setUseWaterTypeName(userWaterTypeName);
                        userBean.setUseWaterType(waterTypeMap.get(userWaterTypeName));
                    } else {
                        throw new RuntimeException("用水类型不能为空");
                    }

                    // 表井形式
                    String meterBjxsName = map.get("meterBjxsName");
                    if (StringUtils.isNotBlank(meterBjxsName)) {
                        if (!BJXSMap.containsKey(meterBjxsName)) {
                            throw new RuntimeException("请输入正确的表井形式");
                        }
                        userBean.setMeterBjxs(BJXSMap.get(meterBjxsName));
                    }

                    // 水表表身码
                    MsInfoDto msInfo = msInfoMap.get(StringUtils.trim(map.get("factoryNo")));
                    if (msInfo == null) {
                        throw new RuntimeException("系统中不存在该表身码信息");
                    }

                    //设置返回数据中的用户主键
                    userBean.setId(map.get("userInfoTempId"));
                    pjMeter.setUserInfoTempId(map.get("userInfoTempId"));
                    //设置接口返回数据中的用户编号
                    userBean.setUserNo(map.get("userNo"));
                    //设置接口返回数据中的客户名称
                    userBean.setCtmName(map.get("ctmName"));
                    //  水表安装地址
                    userBean.setSetupMeterAddr(map.get("setupMeterAddr"));
                    //  施工人员(中文名)
                    String meterBuilder = map.get("meterBuilder");
                    if (StringUtils.isNotBlank(meterBuilder) && orgUserMap != null) {
                        String account = orgUserMap.get(meterBuilder);
                        if (StringUtils.isNotEmpty(account)){
                            userBean.setMeterBuilder(account);
                            userBean.setMeterBuilderName(meterBuilder);
                        }else {
                            throw new RuntimeException("系统中不存在该施工人员信息");
                        }
                    }
                    //  表位
                    userBean.setMeterSite(map.get("meterSite"));

                    //  水表起码
                    String lastReadingNum = map.get("lastReadingNum");
                    if (StringUtils.isNotEmpty(lastReadingNum)) {
                        userBean.setLastReadingNum(Integer.parseInt(map.get("lastReadingNum")));
                    } else {
                        //设置最后抄码默认值，避免为空
                        userBean.setLastReadingNum(0);
                    }
                    //  水表安装日期
                    userBean.setSetupMeterDate(map.get("setupMeterDate"));
                    //  集中器
                    userBean.setConcentratorNo(map.get("concentratorNo"));
                    //  总表编号
                    userBean.setFatherMeterNo(map.get("fatherMeterNo"));
                    //  水表号
                    userBean.setMeterNo(msInfo.getMeterNo());
                    pjMeter.setMsInfoId(msInfo.getId());
                    msInfoDto.setFactoryNo(msInfo.getFactoryNo());
                    // 水表计划安装日期
                    String planMeterInstallDate = map.get("planMeterInstallDate");
                    if (StringUtils.isNotEmpty(planMeterInstallDate)) {
                        pjMeter.setPlanMeterInstallDate(Tools.getDate(planMeterInstallDate));
                    }
                    pjMeter.setUserInfo(userBean);
                    pjMeter.setMsInfo(msInfoDto);
                    pjMeterList.add(pjMeter);
                    row++;
                }
            } catch (Exception e) {
                logger.error("第：" + row + "行：", e);
                return MessageBean.create(Constant.MESSAGE_INT_FAIL, "第" + row + "行：" + e.getMessage(), null);
            }
            // 4. 返回数据
            MessageBean<List> msg = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "工程报装-施工计划/工程施工-水表信息导入成功", List.class);
            msg.setData(pjMeterList);
            return msg;
        } catch (Exception e) {
            factory.close(false);
            logger.error("工程报装-施工计划/工程施工-水表导入失败", e);
            return MessageBean.create(Constant.MESSAGE_INT_FAIL, "工程报装-施工计划/工程施工-水表导入失败："+e.getMessage(), null);
        }
    }

    /**
     * 校验导入数据用户编号
     *
     * @param factory
     * @param data          导入数据
     * @param pjMeterQuery  前端接口入参
     * @param userInfo      登录用户
     * @param userNoEmpty  用户编号是否可以为空
     * @return
     */
    public static void checkImportUserNo(SessionFactory factory, List<Map<String, String>> data, PjMeterQuery pjMeterQuery, UserInfoBean userInfo, boolean userNoEmpty) {
        //获取报装水表-用户mapper
        PjMeterMapper pjMeterMapper = factory.getMapper(PjMeterMapper.class);
        //获取用户mapper
        UserInfoMapper userInfoMapper = factory.getMapper(UserInfoMapper.class);
        //用于存放根据报装单据关联的旧水表关联信息
        List<PjMeter> oldPjMeterList = new ArrayList<>();
        //用于存放导入数据根据用户编号分组之后的数据
        Map<String, List<Map<String, String>>> userNoGroup = new HashMap<>();
        //用于存放旧水表信息根据用户编号分组之后的用户信息
        Map<String, List<UserBean>> oldUserGroup = new HashMap<>();
        //判断入参是否为空、单据id是否为空
        if (ObjectUtil.isNotNull(pjMeterQuery) && StringUtils.isNotBlank(pjMeterQuery.getConsultId())) {
            //查询旧水表关联信息
            oldPjMeterList = pjMeterMapper.getList(pjMeterQuery);
            //获取旧水表信息关联的用户临时表主键id
            List<String> userInfoTempIdList = oldPjMeterList.stream().map(PjMeter::getUserInfoTempId).collect(Collectors.toList());
            //导入数据根据用户编号进行分组
            userNoGroup = data.stream().filter(x->{ return StringUtils.isNotBlank(x.get("userNo"));}).collect(Collectors.groupingBy(x -> x.get("userNo")));
            //初始化一个用户查询查询实体类，用于查询旧用户信息
            UserInfoQueryBean userInfoQueryBean = new UserInfoQueryBean();
            //设置查询条件：用户主键id集合
            userInfoQueryBean.setIdList(userInfoTempIdList);
            //查询旧用户信息
            List<UserBean> userBeanList = userInfoMapper.getList(userInfoQueryBean, UserBean.USERTEMP);
            //旧用户信息根据用户编号进行分组
            oldUserGroup = userBeanList.stream().collect(Collectors.groupingBy(UserBean::getUserNo));
        }
        //创建一个计数器用于记录行数，准确提示导入数据错误行数
        int row = 1;
        // 1. 循环获取数据
        //捕获异常对导入数据进行准确提示
        try {
            //获取系统生成的编号应该只是起到位数
            GenerateNumber generateNumber = new GenerateNumberImpl();
            String userNo1 = generateNumber.getUserNo(factory, "USER_INFO", userInfo.getCurWaterCode());
            //循环处理导入数据
            for (Map<String, String> map : data) {
                //获取导入数据的用户编号
                String userNo = map.get("userNo");
                if (StringUtils.isBlank(userNo) && !userNoEmpty){
                    throw new RuntimeException("用户编号不能为空");
                }
                //判断用户编号是否为空
                if (StringUtils.isNotBlank(userNo)) {
                    //判断用户编号是否是数字
                    boolean number = NumberUtil.isNumber(userNo);
                    if (!number){
                        throw new RuntimeException("用户编号仅限数字");
                    }
                    if (userNo.length() != userNo1.length()) {
                        throw new UserNoException(userNo + "-用户编号长度错误");
                    }
                    //判断导入文件中是否存在重复的用户编号
                    if (userNoGroup.get(userNo).size() > 1) {
                        throw new RuntimeException("导入文件中用户编号" + userNo + "重复");
                    }
                    //用户编号是否新增:如果是新增调用当前类的校验方法checkUserNo
                    if (!oldUserGroup.containsKey(userNo))  {
                        //校验用户编号是否符合规则
                        checkUserNo(factory, userNo, userInfo);
                    }else{
                        //写入用户临时表主键id用于返回给前端，否则保存接口报错
                        map.put("userInfoTempId",oldUserGroup.get(userNo).get(0).getId());
                    }
                }
                row++;

            }
        } catch (Exception e) {
            //捕获异常准确提示
            factory.close(false);
            logger.error("第：" + row + "行水表信息导入失败，", e);
            throw new RuntimeException("第" + row + "行：" + e.getMessage());
        }
    }


    @Override
    public List<HeaderInfoDto> getHeaderInfo(UserInfoBean userInfo) {
        List<HeaderInfoDto> headerInfos = new ArrayList<HeaderInfoDto>();
        //获取数据源
        String dbEnv = DBSourceUtils.getDbEnv(userInfo.getCurWaterCode());
        //获取配置
        String config = Tools.getConfigValue(dbEnv, PJ_METER_INSTALL);
        //判断配置是否开启
        if (CONFIG_OPEN.equals(config)) {
            //增加表头
            headerInfos.add(new HeaderInfoDto("用户编号", false, "userNo"));
            headerInfos.add(new HeaderInfoDto("客户名称", false, "ctmName"));
        }
        headerInfos.add(new HeaderInfoDto("用水类型", false, "userWaterTypeName"));
        headerInfos.add(new HeaderInfoDto("装表地址", false, "setupMeterAddr"));
        headerInfos.add(new HeaderInfoDto("计划日期", false, "planMeterInstallDate"));
        headerInfos.add(new HeaderInfoDto("施工人员", false, "meterBuilder"));
        headerInfos.add(new HeaderInfoDto("表位", false, "meterSite"));
        headerInfos.add(new HeaderInfoDto("表井模式", false, "meterBjmsName"));
        headerInfos.add(new HeaderInfoDto("表井形式", false, "meterBjxsName"));
        headerInfos.add(new HeaderInfoDto("水表起码", false, "lastReadingNum"));
        headerInfos.add(new HeaderInfoDto("表身码", false, "factoryNo"));
        headerInfos.add(new HeaderInfoDto("装表日期", false, "setupMeterDate"));
        headerInfos.add(new HeaderInfoDto("集中器", false, "concentratorNo"));
        headerInfos.add(new HeaderInfoDto("总表编号", false, "fatherMeterNo"));
        return headerInfos;
    }

    /**
     * 校验新增用户编号是否符合规则
     *
     * @param factory
     * @param userNo 用户编号
     * @param userInfo 登录用户信息
     */
    public static void checkUserNo(SessionFactory factory, String userNo, UserInfoBean userInfo) {
        CodeRuleMapper ruleMapper = factory.getMapper(CodeRuleMapper.class, "_default");
        UserInfoMapper userInfoMapper = factory.getMapper(UserInfoMapper.class);
        TWaterCompanyMapper waterCompanyMapper = factory.getMapper(TWaterCompanyMapper.class, "_default");
        // 获取用户编号的编码规则
        CodeRuleBean userNoRule = ruleMapper.findCodeRuleByCode(USER_NO_RULE_CODE);
        if (userNoRule == null) {
            throw new UserNoException("用户编码规则不存在");
        }
        String first = userNoRule.getRuleExp().substring(0, 1);
        //获取水司编号
        String curWaterCode = userInfo.getCurWaterCode();
        TWaterCompanyBean newWaterCompany = waterCompanyMapper.selectByCode(curWaterCode);
        if (newWaterCompany == null) {
            throw new UserNoException("水司编号不存在");
        }
        String simplifyNo = newWaterCompany.getSimplifyNo();
        String checkNo = first + simplifyNo;

        String userNoPrefix = userNo.substring(0, 4);
        // 不符合规范
        if (!userNoPrefix.equals(checkNo) || !StringUtils.isNumeric(userNo)) {
            throw new UserNoException(userNo + "-用户编号前4位错误");
        }

        // 通过户号查询 用户临时表以及用户正式表的数量 如果大于1 表身用户编号已存在
        int iCount = userInfoMapper.countByUserNo(userNo);

        // 用户编号重复
        if (iCount > 0) {
            throw new UserNoException(userNo + "-用户编号已存在");
        }
    }

    @Override
    public boolean isCheckHeader() {
        // TODO Auto-generated method stub
        return true;
    }
}
